home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / powervww / pvitems.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-05  |  35.6 KB  |  1,618 lines

  1. //  ____________________________________________________
  2. // |                                                    |
  3. // |  Project:     POWER VIEW INTERFACE                 |
  4. // |  File:        PVITEMS.CPP                          |
  5. // |  Compiler:    WPP386 (10.6)                        |
  6. // |                                                    |
  7. // |  Subject:     Base class for PV items              |
  8. // |                                                    |
  9. // |  Author:      Emil Dotchevski                      |
  10. // |____________________________________________________|
  11. //
  12. // E-mail: zajo@geocities.com
  13. // URL:    http://www.geocities.com/SiliconValley/Bay/3577
  14.  
  15. #define uses_app
  16. #define uses_colors
  17. #define uses_dc
  18. #define uses_desk
  19. #define uses_help
  20. #define uses_system
  21.  
  22. #define DECLARE_PVITEMS
  23. #include "PVuses.h"
  24. #undef DECLARE_PVITEMS
  25.  
  26. #ifndef NOHELP
  27. static uint help_context = 0;
  28. #endif
  29. static void *command_information = NULL;
  30. static uint command_size = 0;
  31.  
  32. boolean is_valid( Titem *item )
  33. {
  34.   if( ( item != NULL ) && item->valid( cmVALID ) ) return 1;
  35.   DELETE( item );
  36.   return 0;
  37. }
  38.  
  39. #ifndef NOHELP
  40. void _help( uint hlp_ctx )
  41. {
  42.   if( !help_context ) help_context = hlp_ctx;
  43. }
  44.  
  45. uint __help( void )
  46. {
  47.   uint h;
  48.  
  49.   h = help_context;
  50.   help_context = 0;
  51.   return h;
  52. }
  53. #endif
  54.  
  55. void _command_info( void *cmd_info, uint cmd_size )
  56. {
  57.   command_information = cmd_info;
  58.   command_size = cmd_size;
  59. }
  60.  
  61. Titem *message( Titem *receiver, uint command )
  62. {
  63.   if( receiver != NULL )
  64.     return receiver->handle_command( receiver, command );
  65.   else
  66.     return NULL;
  67. }
  68.  
  69. Titem *broadcast( uint command )
  70. {
  71.   return application->handle_command( NULL, command );
  72. }
  73.  
  74. Titem *modal_broadcast( uint command )
  75. {
  76.   if( modal_item != NULL )
  77.     return modal_item->handle_command( NULL, command );
  78.   else
  79.     return NULL;
  80. }
  81.  
  82. //Titem publics:
  83.  
  84. /*
  85.   Description:
  86.     Construct item with given bounds.
  87.   Entry:
  88.     _xl, _yl: item width,heigh.
  89. */
  90. Titem::Titem( int _xl, int _yl )
  91. {
  92.   flags_word = ifVISIBLE+ifSELECTABLE+ifCLOSEABLE+ifMOVABLE+ifRESIZEABLE+ifTAB_STOP;
  93.   state_word = 0;
  94.   event_mask = evCOMMAND+evKEYBOARD;
  95. #ifndef NOMOUSE
  96.   event_mask |= evMOUSE_DOWN+evMOUSE_UP+evMOUSE_DRAG;
  97. #endif
  98.   next = NULL;
  99.   owner = NULL;
  100.   last = NULL;
  101.   current = NULL;
  102.   bound_x = x = 0;
  103.   bound_y = y = 0;
  104.   bound_xl = xl = _xl;
  105.   bound_yl = yl = _yl;
  106.   curs_x = 0;
  107.   curs_y = 0;
  108.   curs_type = 0;
  109.   grow_mode = gmDONT_GROW;
  110.   drag_mode = dmDONT_DRAG;
  111. #ifndef NOHELP
  112.   help_ctx = __help();
  113. #endif
  114.   drop_id = 0;
  115.   stop_state = 0;
  116.   backgrnd_attr = 0;
  117.   backgrnd_char = ' ';
  118.   items_changed = 0;
  119.   set_state( isVALID+isACTIVE, 1 );
  120. }
  121.  
  122. /*
  123.   Description:
  124.     Dispose all subitems. Exclude self from the owner's list.
  125. */
  126. Titem::~Titem( void )
  127. {
  128.   while( last != NULL )
  129.     if( last->flags( ifSTAY ) )
  130.       remove( last );
  131.     else
  132.       DELETE( last );
  133.   if( owner != NULL ) owner->remove( this );
  134.   cancel_update( this );
  135. }
  136.  
  137. /*
  138.   Description:
  139.     Returns pointer to the first (topmost) sub-item, or NULL.
  140. */
  141. Titem *Titem::first( void )
  142. {
  143.   if( last != NULL )
  144.     return last->next;
  145.   else
  146.     return NULL;
  147. }
  148.  
  149. /*
  150.   Description:
  151.     Returns pointer to the previous sub-item in the owner's list (circular),
  152.     or NULL if item has no owner;
  153. */
  154. Titem * Titem::prev( void )
  155. {
  156.   Titem *p;
  157.  
  158.   if( owner == NULL )
  159.     return NULL;
  160.   else
  161.   {
  162.     p = this;
  163.     while( p->next != this)
  164.     {
  165.       p = p->next;
  166.     }
  167.     return p;
  168.   }
  169. }
  170.  
  171. /*
  172.   Description:
  173.     Returns pointer to the next sub-item in the owner's list (linear),
  174.     or NULL if it is the last item, or has no owner;
  175. */
  176. Titem * Titem::nextl( void )
  177. {
  178.   if( ( owner == NULL ) || ( owner->last == this ) )
  179.     return NULL;
  180.   else
  181.     return next;
  182. }
  183.  
  184. /*
  185.   Description:
  186.     Returns pointer to the previous sub-item in the owner's list (linear),
  187.     or NULL if it is the first item, or has no owner;
  188. */
  189. Titem * Titem::prevl( void )
  190. {
  191.   if( ( owner == NULL ) || ( owner->first() == this ) )
  192.     return NULL;
  193.   else
  194.     return prev();
  195. }
  196.  
  197. /*
  198.   Description:
  199.     Set or clear flags_word bits depending on 'enable'. Handle some special
  200.     cases. Can be overriden to handle more special cases.
  201.   Entry:
  202.     _flags_word: requested bit mask;
  203.     enable:      1 - set bits, 0 - clear.
  204. */
  205. void Titem::set_flags( uint _flags_word, boolean enable )
  206. {
  207.   uint f;
  208.  
  209.   if( ( _flags_word & ifSELECTABLE ) && !enable && state( isSELECTED ) )
  210.   {
  211.     set_state( isSELECTED, 0 );
  212.     if( state( isSELECTED ) ) _flags_word &= ~ifSELECTABLE;
  213.   }
  214.   f = flags_word;
  215.   if( enable )
  216.     flags_word |= _flags_word;
  217.   else
  218.     flags_word &= ~_flags_word;
  219.   if( ( f != flags_word ) && ( _flags_word & ifVISIBLE ) ) redraw();
  220. }
  221.  
  222. /*
  223.   Description:
  224.     Set or clear state bits depending on 'enable'. Handle some special
  225.     cases. Can be overriden to handle more special cases.
  226.   Entry:
  227.     _state_word: requested bit mask;
  228.     enable:      1 - set bits, 0 - clear.
  229. */
  230. void Titem::set_state( uint _state_word, boolean enable )
  231. {
  232.   uint s, ns;
  233.   boolean f;
  234.   Titem *p;
  235.  
  236.   if( enable )
  237.   {
  238.     if( ( _state_word & isACTIVE ) &&
  239.           flags( ifSELECTABLE ) && !state( isSELECTED ) )
  240.       _state_word &= ~isACTIVE;
  241.     if( ( _state_word & isACCESSABLE ) && !event_mask )
  242.       _state_word &= ~isACCESSABLE;
  243.     if( ( _state_word & isALIVE ) && ( !flags( ifVISIBLE ) || state( isHIDDEN ) ) )
  244.       _state_word &= ~isALIVE;
  245.     if( ( _state_word & isSELECTED ) &&
  246.         ( !flags(ifSELECTABLE) || owner==NULL ||
  247.           ( ( ( p = owner->current ) != NULL ) &&
  248.             ( p->set_state( isSELECTED, 0 ),
  249.               p->state( isSELECTED )
  250.             )
  251.           )
  252.         )
  253.       )
  254.       _state_word &= ~isSELECTED;
  255.   }
  256.   else
  257.     if( ( _state_word & isSELECTED ) && state( isFOCUSED ) && !release_focus() )
  258.       _state_word &= ~isSELECTED;
  259.   if( enable ) ns = state_word | _state_word; else ns = state_word & ~_state_word;
  260.   if( state_word == ns ) return;
  261.   s = _state_word & ( isACTIVE+isALIVE+isDISABLED+isACCESSABLE );
  262.   if( s )
  263.     for( p=first(); p!=NULL; p=p->nextl() )
  264.       p->set_state( s, enable );
  265.   f = ( ( _state_word & ( isFOCUSED+isSELECTED+isDISABLED+isHIDDEN ) ) != 0 );
  266.   if( f ) redraw();
  267.   s = state_word; state_word = ns;
  268.   if( ( state_word & isHIDDEN ) != ( s & isHIDDEN ) )
  269.   {
  270.     set_state( isALIVE, !enable && owner && owner->state( isALIVE ) );
  271.     if( owner != NULL )
  272.       if( enable )
  273.         req_update( owner );
  274.       else
  275.         owner->update_bounds( this );
  276.   }
  277.   if( ( state_word & isDISABLED ) != ( s & isDISABLED ) )
  278.     set_state( isACTIVE, !enable );
  279.   if( ( state_word & isSELECTED ) != ( s & isSELECTED ) )
  280.   {
  281.     set_state( isACTIVE, enable );
  282.     if( owner != NULL )
  283.       if( enable )
  284.       {
  285.         owner->current = this;
  286.         p = owner;
  287.         while( ( p != modal_item ) && ( p->owner != NULL ) && ( p->owner->current == p ) )
  288.           p = p->owner;
  289.         if( p == modal_item ) set_state( isFOCUSED, 1 );
  290.       }
  291.       else
  292.       {
  293.         owner->current = NULL;
  294.         set_state( isFOCUSED, 0 );
  295.       }
  296.   }
  297.   if( ( state_word & isFOCUSED ) != ( s & isFOCUSED ) )
  298.   {
  299.     if( enable ) get_focused();
  300.     if( current != NULL ) current->set_state( isFOCUSED, enable );
  301.   }
  302.   if( f ) redraw();
  303.   if( ( state_word & isMODAL ) != ( s & isMODAL ) )
  304.   {
  305.     set_state( isACCESSABLE, enable );
  306.     if( enable ) set_state( isACTIVE, 1 );
  307.   }
  308.   if( ( _state_word & isON_TOP ) && owner )
  309.     if( enable )
  310.       owner->pop_item( this );
  311.     else
  312.       owner->do_pop_top_items( owner->last );
  313. }
  314.  
  315. /*
  316.   Description:
  317.     Test state of the item's owner just before desktop or application.
  318.     Usually used to determine is the window that (indirectly) owns the
  319.     item active, selected, and so on.
  320. */
  321. boolean Titem::window_state( uint _state_word )
  322. {
  323.   Titem *p;
  324.  
  325.   p = this;
  326.   while( p->owner != NULL )
  327.   {
  328.     if( ( p->owner == desktop ) || ( p->owner == application ) )
  329.       return p->state( _state_word );
  330.     p = p->owner;
  331.   }
  332.   return 0;
  333. }
  334.  
  335. /*
  336.   Description:
  337.     Focus the item. Returns 0 if not successfull. This may be because
  338.     another item do not release the focus.
  339. */
  340. boolean Titem::focus( void )
  341. {
  342.   if( state(isDISABLED) ) return 0;
  343.   if( ( owner == NULL ) || state( isFOCUSED|isMODAL ) ) return 1;
  344.   if( owner->focus() )
  345.   {
  346.     set_state( isSELECTED, 1 );
  347.     return state( isSELECTED );
  348.   }
  349.   return 0;
  350. }
  351.  
  352. /*
  353.   Description:
  354.     Called when item is mouse-clicked. Original pop_up does nothing but
  355.     calls owner's pop_up.
  356. */
  357. void Titem::pop_up( void )
  358. {
  359.   if( owner != NULL ) owner->pop_up();
  360. }
  361.  
  362. /*
  363.   Description:
  364.     Select next or previous tabstop item, depending on direction.
  365. */
  366. void Titem::tab_next( int direction )
  367. {
  368.   Titem *p;
  369.   boolean ts, dis, tab;
  370.  
  371.   if( ( last == NULL ) || ( current == NULL ) ) return;
  372.   ts = 0;
  373.   p = current;
  374.   do
  375.   {
  376.     if( direction>0 ) p = p->next; else p = p->prev();
  377.     dis = p->state( isDISABLED );
  378.     tab = p->flags( ifTAB_STOP );
  379.     if( tab ) ts = dis;
  380.   }
  381.   while( ( !p->flags( ifSELECTABLE ) || !p->state( isALIVE ) || dis || (!tab && !ts) ) && ( p != current ) );
  382.   if( p != current ) p->focus();
  383. }
  384.  
  385. /*
  386.   Description:
  387.     Select next or previous item (depending on direction) between two
  388.     tabstop items.
  389. */
  390. void Titem::local_next( int direction )
  391. {
  392.   Titem *p;
  393.  
  394.   if( ( last == NULL ) || ( current == NULL ) || ( ( direction>0 ) && ( current->flags( ifTAB_STOP ) ) ) ) return;
  395.   p = current;
  396.   do
  397.   {
  398.     if( direction>0 ) p = p->next; else p = p->prev();
  399.   }
  400.   while( ( !p->flags( ifSELECTABLE ) || !p->state( isALIVE ) || p->state( isDISABLED ) ) && ( p != current ) );
  401.   if( ( p != current ) && ( ( direction>0 ) || !p->flags( ifTAB_STOP ) ) ) p->focus();
  402. }
  403.  
  404. /*
  405.   Description:
  406.     Modify item events mask.
  407.   Entry:
  408.     mask:   events to modify;
  409.     enable: 1 - enable events, 0 - disable.
  410. */
  411. void Titem::set_events_mask( uint mask, boolean enable )
  412. {
  413.   if( enable )
  414.   {
  415.     event_mask |= mask;
  416.     application->or_events_mask( this );
  417.   }
  418.   else
  419.   {
  420.     event_mask &= ~mask;
  421.     application->update_events_mask();
  422.   }
  423. }
  424.  
  425. /*
  426.   Description:
  427.     Drag item to to a new location (based on the owner's coordinates).
  428.     Can be overriden to limit item drag region.
  429.   Entry:
  430.     _x, _y: requested new position.
  431. */
  432. void Titem::drag( int _x, int _y )
  433. {
  434.   redraw();
  435.   x = _x; y = _y;
  436.   redraw();
  437.   if( owner != NULL ) owner->update_bounds( this );
  438. }
  439.  
  440. /*
  441.   Description:
  442.     Resize item to a new bounds. Can be overriden to limit item bounds.
  443.   Entry:
  444.     _xl, _yl: requested new width, heigh.
  445. */
  446. void Titem::resize( int _xl, int _yl )
  447. {
  448.   Titem *p;
  449.   int old_xl, old_yl;
  450.  
  451.   redraw();
  452.   old_xl = xl; old_yl = yl;
  453.   xl = _xl; yl = _yl;
  454.   p = first();
  455.   while( p != NULL )
  456.   {
  457.     p->calc_bounds( xl - old_xl, yl - old_yl );
  458.     p = p->nextl();
  459.   }
  460.   redraw();
  461.   optimize_bounds();
  462. }
  463.  
  464. /*
  465.   Description:
  466.     Translate global coordinates to item's local coordinates.
  467.   Entry:
  468.     x1, y1: global coordinates.
  469.   Exit:
  470.     x2, y2: local coordinates.
  471. */
  472. void Titem::make_local( int x1, int y1, int &x2, int &y2 )
  473. {
  474.   Titem *p;
  475.  
  476.   x2 = x1; y2 = y1;
  477.   p = this;
  478.   while( p != NULL )
  479.   {
  480.     x2 -= p->x; y2 -= p->y;
  481.     p = p->owner;
  482.   }
  483. }
  484.  
  485. /*
  486.   Description:
  487.     Translate local coordinates to global screen coordinates.
  488.   Entry:
  489.     x1, y1: local coordinates.
  490.   Exit;
  491.     x2, y2: global coordinates.
  492. */
  493. void Titem::make_global( int x1, int y1, int &x2, int &y2 )
  494. {
  495.   Titem *p;
  496.  
  497.   x2 = x1; y2 = y1;
  498.   p = this;
  499.   while( p != NULL )
  500.   {
  501.     x2 += p->x; y2 += p->y;
  502.     p = p->owner;
  503.   }
  504. }
  505.  
  506. /*
  507.   Description:
  508.     Returns global coordinates of the item's upper-left corner.
  509.   Exit:
  510.     _x, _y: global item coordinates.
  511. */
  512. void Titem::get_origin( int &_x, int &_y )
  513. {
  514.   make_global( 0, 0, _x, _y );
  515. }
  516.  
  517. /*
  518.   Description:
  519.     Determine if the point given by it's global coordinates is inside the
  520.     item. Can be overriden to handle items with a strange form, instead of
  521.     a rectangle.
  522.   Entry:
  523.     _x, _y: global point coordinates.
  524.   Exit:
  525.     1: point is inside the item, 0 - otherwise.
  526. */
  527. boolean Titem::check_inside( int _x, int _y )
  528. {
  529.   int a, b;
  530.  
  531.   get_origin( a, b );
  532.   return ( _x >= a ) && ( _x < ( a + xl ) ) &&
  533.          ( _y >= b ) && ( _y < ( b + yl ) );
  534. }
  535.  
  536. /*
  537.   Description:
  538.     Invalidate item rectangle, cousing item (or it's buffer, if item is
  539.     buffered) to be redrawn during next screen update loop.
  540. */
  541. void Titem::redraw( void )
  542. {
  543.   int a, b;
  544.  
  545.   if( !state( isALIVE ) ) return;
  546.   get_origin( a, b );
  547.   screen_dc->invalidate( a + bound_x, b + bound_y, bound_xl, bound_yl );
  548. }
  549.  
  550. /*
  551.   Description:
  552.     If message can be handled by the item, handle_event calls event_handler
  553.     and, after that handles some special cases.
  554.   Note:
  555.     if a command message successfully handled, and if info isn't NULL, and
  556.     size isn't 0, then command info is disposed.
  557.   Entry:
  558.     ev: event to be handled.
  559. */
  560. void Titem::handle_event( Tevent &ev )
  561. {
  562.   Titem *p;
  563.   Titem *c;
  564.  
  565.   if( ( last != NULL ) && ( !state( isICONIZED ) || ev.code==evCOMMAND ) )
  566.   {
  567.     items_changed = 0;
  568.     p = first();
  569.     while( p != NULL )
  570.     {
  571.       if( p->flags( ifPRE_PROCESS ) && ( p != master_modal ) ) p->handle_event( ev );
  572.       if( items_changed ) goto skip;
  573.       p = p->nextl();
  574.     }
  575.     c = NULL;
  576.     if( ( ev.code & ( evKEYBOARD|evCOMMAND ) ) && ( current ) )
  577.     {
  578.       current->handle_event( ev );
  579.       c = current;
  580.     }
  581.     if( !items_changed )
  582.     {
  583.       p = first();
  584.       while( ( p != NULL ) && ( ev.code != evNOTHING ) )
  585.       {
  586.         if( ( p != c ) && !p->flags( ifPRE_PROCESS ) ) p->handle_event( ev );
  587.         if( items_changed ) break;
  588.         p = p->nextl();
  589.       }
  590.     }
  591.   }
  592. skip:
  593.   if( isit_4u( ev ) )
  594.   {
  595.     event_handler( ev );
  596.     if( ( ev.code == evCOMMAND ) && ( ev.destination == this ) )
  597.     {
  598.       switch( ev.CMD_CODE )
  599.       {
  600.         case cmDONE:
  601.           if( valid( cmDONE ) && ( !state( isSELECTED ) || release_focus() ) )
  602.           {
  603.             if( state( isMODAL ) )
  604.             {
  605.               put_command( this, cmDONE );
  606.               stop( cmDONE );
  607.             }
  608.             else
  609.               DELETE( this );
  610.             break;
  611.           }
  612.           ev.destination = NULL;
  613.           return;
  614.         case cmFOCUS:
  615.           focus(); break;
  616.         case cmSELECT:
  617.           set_state( isSELECTED, 1 ); break;
  618.         case cmENABLE:
  619.           set_state( isDISABLED, 0 ); break;
  620.         case cmDISABLE:
  621.           set_state( isDISABLED, 1 ); break;
  622.         case cmHIDE:
  623.           set_state( isHIDDEN, 1 ); break;
  624.         case cmSHOW:
  625.           set_state( isHIDDEN, 0 ); break;
  626.         default:
  627.           return;
  628.       }
  629.       handled( ev );
  630.     }
  631.   }
  632. }
  633.  
  634. /*
  635.   Description:
  636.     Construct a command message and call handle_event.
  637.     Use 'command_info' prefix to specify command info ptr and size.
  638.   Note:
  639.     If info isn't NULL, and size isn't 0, then command info is disposed.
  640.   Entry:
  641.     receiver: pointer to the receiver, or NULL;
  642.     cmd_code: command code.
  643.   Exit:
  644.     evNOTHING if command has been serviced.
  645. */
  646. Titem *Titem::handle_command( Titem *receiver, uint cmd_code )
  647. {
  648.   Tevent ev;
  649.  
  650.   ev.code = evCOMMAND;
  651.   ev.priority = 0;
  652.   ev.destination = receiver;
  653.   ev.CMD_CODE = cmd_code;
  654.   ev.CMD_INFO = command_information;
  655.   ev.CMD_SIZE = command_size;
  656.   command_size = 0;
  657.   command_information = NULL;
  658.   handle_event( ev );
  659.   return (Titem *) ev.destination;
  660. }
  661.  
  662. /*
  663.   Description:
  664.     Determine if the exec loop can be terminated via stop_code. Can be
  665.     overriden to handle special cases.
  666.   Entry:
  667.     stop_code.
  668.   Exit:
  669.     1 if item allows current modal loop to be terminated by stop_code,
  670.     0 otherwise.
  671. */
  672. boolean Titem::valid( uint command )
  673. {
  674.   Titem *p;
  675.  
  676.   if( !state( isVALID ) ) return 0;
  677.   p = first();
  678.   while( p != NULL )
  679.   {
  680.     if( !p->valid( command ) ) return 0;
  681.     p = p->nextl();
  682.   }
  683.   return 1;
  684. }
  685.  
  686. /*
  687.   Description:
  688.     Main modal loop method. Collect and pass events to the handle_event()
  689.     until a call to stop() occurred.
  690.   Exit:
  691.     Return stop code passed to stop().
  692. */
  693. uint Titem::exec( void )
  694. {
  695.   Titem *save_modal, *save_current;
  696.   Tevent ev;
  697.  
  698.   optimize_bounds();
  699.   save_modal = modal_item;
  700.   if( save_modal != NULL ) save_modal->set_state( isMODAL+isFOCUSED, 0 );
  701.   modal_item = this;
  702.   set_state( isMODAL+isFOCUSED, 1 );
  703.   if( owner != NULL )
  704.   {
  705.     save_current = owner->current;
  706.     owner->current = this;
  707.   }
  708.   if( current != NULL ) current->focus();
  709.   for( stop_state=0; stop_state==0; )
  710.   {
  711.     get_event( ev );
  712.     handle_event( ev );
  713.   }
  714.   if( owner != NULL ) owner->current = save_current;
  715.   set_state( isMODAL+isFOCUSED, 0 );
  716.   modal_item = save_modal;
  717.   if( modal_item != NULL ) modal_item->set_state( isMODAL+isFOCUSED, 1 );
  718.   return stop_state;
  719. }
  720.  
  721. /*
  722.   Description:
  723.     Include item, execute it, then exclude it.
  724.   Entry:
  725.     p:      pointer to the item to be executed;
  726.     _x, _y: coordinates for the item.
  727.   Exit:
  728.     Exec stop code.
  729. */
  730. uint Titem::exec_item( Titem *p, int _x, int _y )
  731. {
  732.   uint result;
  733.  
  734.   if( p != NULL )
  735.   {
  736.     put_in( p, _x, _y );
  737.     result = p->exec();
  738.     remove( p );
  739.     return result;
  740.   }
  741.   else
  742.     return cmCANCEL;
  743. }
  744.  
  745. /*
  746.   Description:
  747.     Includes item in the list of subitems.
  748.   Entry:
  749.     v:      pointer to the item to be included;
  750.     _x, _y: item coordinates.
  751. */
  752. void Titem::put_in( Titem *v, int _x, int _y )
  753. {
  754.   v->x = _x; v->y = _y;
  755.   if( v->x == xCENTER ) v->x = ( xl - v->xl ) >> 1;
  756.   if( v->y == yCENTER ) v->y = ( yl - v->yl ) >> 1;
  757.   if( v->xl == xlMAX ) v->resize( xl, v->yl );
  758.   if( v->yl == ylMAX ) v->resize( v->xl, yl );
  759.   v->owner = this;
  760.   if( last == NULL )
  761.     v->next = v, last = v;
  762.   else
  763.     v->next = last->next, last->next = v;
  764.   v->set_state( state_word & ( isACTIVE+isALIVE+isACCESSABLE+isDISABLED ), 1 );
  765.   v->initialize();
  766.   v->calc_bounds( 0, 0 );
  767.   v->redraw();
  768. #ifndef NOHELP
  769.   v->get_help_ctx();
  770. #endif
  771.   application->or_events_mask( v );
  772.   if( v->flags( ifSELECTABLE ) && !v->state( isHIDDEN ) )
  773.     v->set_state( isSELECTED, 1 );
  774.   items_changed = 1;
  775.   pop_top_items();
  776.   update_bounds( v );
  777. }
  778.  
  779. /*
  780.   Description:
  781.     Exclude a subitem from the subitems list.
  782.   Entry:
  783.     v: pointer to the item to be excluded.
  784.   Exit:
  785.     0 if item !found in the subitems list,
  786.     1 otherwise.
  787. */
  788. boolean Titem::remove( Titem *v )
  789. {
  790.   boolean f;
  791.   Titem *l;
  792.   Titem *p;
  793.  
  794.   p = last;
  795.   do
  796.   {
  797.     l = p;
  798.     p = p->next;
  799.     if( p == v )
  800.     {
  801.       if( ( f = ( current == v ) ) != 0 )
  802.       {
  803.         v->set_state( isSELECTED, 0 );
  804.         if( v->state( isSELECTED ) ) break;
  805.       }
  806.       v->redraw();
  807.       if( p == l )
  808.         last = NULL;
  809.       else
  810.       {
  811.         l->next = p->next;
  812.         if( p == last ) last = l;
  813.       }
  814.       if( f )
  815.       {
  816.         f = !v->state( isON_TOP );
  817.         do
  818.         {
  819.           f = !f;
  820.           for( p=first(); p!=NULL; p=p->nextl() )
  821.             if( p->flags(ifSELECTABLE) && p->state(isALIVE) && (f || !p->state(isON_TOP)) )
  822.             {
  823.               p->set_state( isSELECTED, 1 );
  824.               f = 1;
  825.               break;
  826.             }
  827.         }
  828.         while( !f );
  829.       }
  830.       v->next = NULL;
  831.       v->owner = NULL;
  832.       application->update_events_mask();
  833.       items_changed = 1;
  834.       req_update( this );
  835.       return 1;
  836.     }
  837.   }
  838.   while( p != last );
  839.   return 0;
  840. }
  841.  
  842. /*
  843.   Description:
  844.     Update bounds as subitem was moved/resized. This do not obtain min bounds
  845.     for the item, it can only enlarge bounding rectangle. Min bounds are
  846.     calculated at idle time calling optimize_bounds.
  847.   Entry:
  848.     p - subitem that has been moved/resized.
  849.   Note:
  850.     p must be valid subitem pointer.
  851. */
  852. void Titem::update_bounds( Titem *p )
  853. {
  854.   int sx, sy, bx, by, xx, yy;
  855.  
  856.   if( p->flags( ifVISIBLE ) && !p->state( isHIDDEN ) )
  857.   {
  858.     make_global( bound_x, bound_y, sx, sy );
  859.     p->make_global( p->bound_x, p->bound_y, bx, by );
  860.     xx = sx - bx;
  861.     yy = sy - by;
  862.     if( xx > 0 )
  863.     {
  864.       bound_xl += xx;
  865.       sx = bx;
  866.     }
  867.     if( yy > 0 )
  868.     {
  869.       bound_yl += yy;
  870.       sy = by;
  871.     }
  872.     xx = ( bx + p->bound_xl ) - ( sx + bound_xl );
  873.     yy = ( by + p->bound_yl ) - ( sy + bound_yl );
  874.     if( xx > 0 ) bound_xl += xx;
  875.     if( yy > 0 ) bound_yl += yy;
  876.     make_local( sx, sy, bound_x, bound_y );
  877.     req_update( this );
  878.     if( owner != NULL ) owner->update_bounds( this );
  879.   }
  880. }
  881.  
  882. /*
  883.   Description:
  884.     Optimize bounding rectangle by calling update_bounds for each subitem.
  885. */
  886. void Titem::optimize_bounds( void )
  887. {
  888.   int sx, sy, bx, by, xx, yy;
  889.   Titem *p;
  890.  
  891.   bound_xl = xl; bound_yl = yl;
  892.   if( state( isICONIZED ) )
  893.   {
  894.     bound_x = 0;
  895.     bound_y = 0;
  896.   }
  897.   else
  898.   {
  899.     get_origin( sx, sy );
  900.     p = first();
  901.     while( p != NULL )
  902.     {
  903.       if( p->flags( ifVISIBLE ) && !p->state( isHIDDEN ) )
  904.       {
  905.         p->optimize_bounds();
  906.         p->make_global( p->bound_x, p->bound_y, bx, by );
  907.         xx = sx - bx;
  908.         yy = sy - by;
  909.         if( xx > 0 )
  910.         {
  911.           bound_xl += xx;
  912.           sx = bx;
  913.         }
  914.         if( yy > 0 )
  915.         {
  916.           bound_yl += yy;
  917.           sy = by;
  918.         }
  919.         xx = ( bx + p->bound_xl ) - ( sx + bound_xl );
  920.         yy = ( by + p->bound_yl ) - ( sy + bound_yl );
  921.         if( xx > 0 ) bound_xl += xx;
  922.         if( yy > 0 ) bound_yl += yy;
  923.       }
  924.       p = p->nextl();
  925.     }
  926.     make_local( sx, sy, bound_x, bound_y );
  927.   }
  928. }
  929.  
  930. /*
  931.   Description:
  932.     Move specified item to the front of the subitems list, but after the
  933.     'always on top' items.
  934.   Entry:
  935.     w: pointer to the item to be moved to front.
  936. */
  937. void Titem::pop_item( Titem *w )
  938. {
  939.   Titem *p, *l;
  940.  
  941.   if( ( last == NULL ) || ( last->next == w ) ) return;
  942.   p = last;
  943.   do
  944.   {
  945.     l = p;
  946.     p = p->next;
  947.     if( p == w )
  948.     {
  949.       p->redraw();
  950.       if( p == last )
  951.         last = l;
  952.       else
  953.       {
  954.         l->next = p->next;
  955.         p->next = last->next;
  956.         last->next = p;
  957.       }
  958.       items_changed = 1;
  959.       pop_top_items();
  960.       break;
  961.     }
  962.   }
  963.   while( p != last );
  964. }
  965.  
  966. //Titem protected:
  967.  
  968. /*
  969.   Description:
  970.     Called when item gets focused.
  971. */
  972. void Titem::get_focused( void )
  973. {
  974. }
  975.  
  976. /*
  977.   Description:
  978.     Called when item loose focus. Return 0 if the item want to keep
  979.     the focus.
  980. */
  981. boolean Titem::release_focus( void )
  982. {
  983.   if( current != NULL ) return current->release_focus();
  984.   return 1;
  985. }
  986.  
  987. /*
  988.   Description:
  989.     Called when item has been just inserted in another item, and whenever
  990.     its owner has been resized. Can be overriden to drag item when owner
  991.     resizes, etc.
  992. */
  993. void Titem::calc_bounds( int delta_xl, int delta_yl )
  994. {
  995.   int _x, _y, _xl, _yl, old_xl, old_yl;
  996.  
  997.   old_xl = owner->xl - delta_xl; old_yl = owner->yl - delta_yl;
  998.   if( ( !old_xl ) || ( !old_yl ) ) return;
  999.   _x = x; _y = y; _xl = xl; _yl = yl;
  1000.   if( drag_mode & dmDRAG_HOR )
  1001.     if( drag_mode & dmDRAG_REL )
  1002.       _x = ( x * xl ) / old_xl;
  1003.     else
  1004.       _x = x + delta_xl;
  1005.   if( drag_mode & dmDRAG_VER )
  1006.     if( drag_mode & dmDRAG_REL )
  1007.       _y = ( y * yl ) / old_yl;
  1008.     else
  1009.       _y = y + delta_yl;
  1010.   if( grow_mode & gmGROW_HOR )
  1011.     if( grow_mode & gmGROW_REL )
  1012.       _xl = ( xl * xl ) / old_xl;
  1013.     else
  1014.       _xl = xl + delta_xl;
  1015.   if( grow_mode & gmGROW_VER )
  1016.     if( grow_mode & gmGROW_REL )
  1017.       _yl = ( yl * yl ) / old_yl;
  1018.     else
  1019.       _yl = yl + delta_yl;
  1020.   if( (  _x != x  ) || (  _y != y  ) ) drag( _x, _y );
  1021.   if( ( _xl != xl ) || ( _yl != yl ) ) resize( _xl, _yl );
  1022. }
  1023.  
  1024. /*
  1025.   Description:
  1026.     A heavy item draw can call get_clip_rect to obtain actual bounds of the
  1027.     rectangle that need to be redrawn.
  1028.   Note:
  1029.     Returned coordinates are converted to local.
  1030. */
  1031. void Titem::get_clip_rect( int &_x, int &_y, int &_xl, int &_yl )
  1032. {
  1033.   _x = current_dc->x + current_dc->region_x;
  1034.   _y = current_dc->y + current_dc->region_y;
  1035.   _xl = current_dc->region_xl;
  1036.   _yl = current_dc->region_yl;
  1037.   make_local( _x, _y, _x, _y );
  1038.   if( _x < 0 ) _xl += _x, _x = 0;
  1039.   if( _y < 0 ) _yl += _y, _y = 0;
  1040.   if( _xl > xl ) _xl = xl;
  1041.   if( _yl > yl ) _yl = yl;
  1042. }
  1043.  
  1044. /*
  1045.   Description:
  1046.     Determine if the item is in colision with the screen DC region. Use
  1047.     to determine if the item is visible on the screen. See PVDC.CPP for
  1048.     details.
  1049.   Exit:
  1050.     0 - neither item or it's subitems are exposed
  1051.     1 - item or it's subitems are exposed
  1052.     2 - item is exposed
  1053. */
  1054. int Titem::exposed( void )
  1055. {
  1056.   int a, b, rx, ry;
  1057.   uint rxl, ryl;
  1058.   int result;
  1059.  
  1060.   get_origin( a, b );
  1061.   rx = screen_dc->region_x;  ry = screen_dc->region_y;
  1062.   rxl = screen_dc->region_xl; ryl = screen_dc->region_yl;
  1063.   result = 0;
  1064.   if( rect_colision( a + bound_x, b + bound_y, bound_xl, bound_yl,
  1065.                      rx,          ry,          rxl,      ryl ) ) result = 1;
  1066.   if( rect_colision( a, b, xl, yl, rx, ry, rxl, ryl ) ) result = 2;
  1067.   current_dc->set_region( rx - current_dc->x, ry - current_dc->y, rxl, ryl );
  1068.   return result;
  1069. }
  1070.  
  1071. /*
  1072.   Description:
  1073.     Call all the subitems paint to update item itself.
  1074. */
  1075. void Titem::reverse_paint( Titem *p )
  1076. {
  1077.   int a, b;
  1078.  
  1079.   p = p->next;
  1080.   if( p != last )
  1081.   {
  1082.     p->get_origin( a, b );
  1083.     if( ( a > current_dc->x ) ||
  1084.         ( b > current_dc->y ) ||
  1085.         ( a + p->xl < current_dc->x + current_dc->xl ) ||
  1086.         ( b + p->yl < current_dc->y + current_dc->yl ) ||
  1087.         !p->state( isALIVE ) ) reverse_paint( p );
  1088.   }
  1089.   p->paint();
  1090. }
  1091.  
  1092. void Titem::paint( void )
  1093. {
  1094.   int is_exposed;
  1095.  
  1096.   if( state( isALIVE ) && ( is_exposed = exposed() ) )
  1097.   {
  1098.     int a, b;
  1099.  
  1100.     if( is_exposed == 2 )
  1101.     {
  1102.       get_origin( a, b );
  1103.       current_dc->set_base( a - current_dc->x, b - current_dc->y );
  1104.       set_palette();
  1105.       draw();
  1106.     }
  1107.     if( !state( isICONIZED ) && last != NULL ) reverse_paint( last );
  1108.   }
  1109. }
  1110.  
  1111. /*
  1112.   Description:
  1113.     Set up palette. Called just before a call to draw. By default calls
  1114.     owner's set palette.
  1115. */
  1116. void Titem::set_palette( void )
  1117. {
  1118.   text_attr = backgrnd_attr;
  1119.   if( text_attr ) return;
  1120.   if( owner != NULL ) owner->set_palette();
  1121. }
  1122.  
  1123. /*
  1124.   Description:
  1125.     Draw the item. Must cover all the item rectangle.
  1126.   On entry:
  1127.     DC base is set to item's upper-left corner, palette is initialized.
  1128. */
  1129. void Titem::draw( void )
  1130. {
  1131.   static char *t = "|r. |l.";
  1132.  
  1133.   if( ( last == NULL ) || !text_attr ) return;
  1134.   t[2] = (char) xl; t[3] = backgrnd_char; t[6] = (char) yl;
  1135.   txt( t );
  1136. }
  1137.  
  1138. /*
  1139.   Description:
  1140.     Called when item has been just inserted in another item.
  1141. */
  1142. void Titem::initialize( void )
  1143. {
  1144. }
  1145.  
  1146. /*
  1147.   Description:
  1148.     Returns 1 if event can be serviced by the item at the moment. Also
  1149.     used to set up local message fields.
  1150.   Entry:
  1151.     ev: event.
  1152. */
  1153. boolean Titem::isit_4u( Tevent &ev )
  1154. {
  1155.   if( ( ( ev.code < evCOMMAND ) && state( isDISABLED ) ) ||
  1156.       ( !( event_mask & ev.code ) ||
  1157.       ( ( ev.destination != NULL ) && ( ev.destination != this ) ) ) )
  1158.     return 0;
  1159.   else
  1160.   {
  1161. #ifndef NOMOUSE
  1162.     if( (ev.code&evMOUSE)
  1163. #ifdef HGR
  1164.      || (ev.code&evHGR_MOUSE)
  1165. #endif
  1166.       )
  1167.       if( state( isALIVE ) )
  1168.       {
  1169.         make_local( ev.GLOBAL_X, ev.GLOBAL_Y, ev.LOCAL_X, ev.LOCAL_Y );
  1170. #ifdef HGR
  1171.         int a, b; get_origin( a, b );
  1172.         ev.LOCAL_HGR_X=ev.GLOBAL_HGR_X-a*8;
  1173.         ev.LOCAL_HGR_Y=ev.GLOBAL_HGR_Y-b*16;
  1174. #endif
  1175.         ev.INSIDE = check_inside( ev.GLOBAL_X, ev.GLOBAL_Y );
  1176.         return 1;
  1177.       }
  1178.       else
  1179.         return 0;
  1180. #endif
  1181.   }
  1182.   return 1;
  1183. }
  1184.  
  1185. /*
  1186.   Description:
  1187.     Service the passed message. If you override this method you shoud call
  1188.     inherited event_handler if you have !serviced the message.
  1189.   Entry:
  1190.     ev: event.
  1191.   Exit:
  1192.     ev.code = evNOTHING if event accepted and serviced.
  1193. */
  1194. void Titem::event_handler( Tevent &ev )
  1195. {
  1196. #ifndef NOHELP
  1197.   if( state( isFOCUSED|isMODAL ) &&
  1198.      ( ( ( ev.code == evCOMMAND )  && ( ev.CMD_CODE == cmHELP ) ) ||
  1199.      ( ( ev.code == evKEY_PRESS ) && ( ev.ASCII == kF1 ) ) ) )
  1200.   {
  1201.     if( state( isALIVE ) )
  1202.       online_help( help_ctx );
  1203.     else
  1204.       online_help( 0 );
  1205.     handled( ev );
  1206.   }
  1207. #endif
  1208. #ifndef NOMOUSE
  1209.   if( ( ev.code == evMOUSE_DOWN ) && ev.INSIDE )
  1210.   {
  1211.     pop_up();
  1212.     if( flags( ifSELECTABLE ) && !state( isFOCUSED ) ) focus();
  1213.   }
  1214. #endif
  1215. }
  1216.  
  1217. /*
  1218.   Description:
  1219.     Call owner's or 'hardware' get_event.
  1220.   Exit:
  1221.     ev: event;
  1222. */
  1223. void Titem::get_event( Tevent &ev )
  1224. {
  1225.   if( owner != NULL )
  1226.     owner->get_event( ev );
  1227.   else
  1228.     ::get_event( ev );
  1229. }
  1230.  
  1231. /*
  1232.   Description:
  1233.     Get (wait for) a mouse event. Returns 0 if event is evMOUSE_UP.
  1234.     Use for dragging items w/ the mouse.
  1235.   Exit:
  1236.     ev: event.
  1237. */
  1238. #ifndef NOMOUSE
  1239. boolean Titem::get_mouse( Tevent &ev, uint mask )
  1240. {
  1241.   mask |= evMOUSE_UP;
  1242.   do
  1243.   {
  1244.     get_event( ev );
  1245.   }
  1246.   while( !isit_4u( ev ) || !( ev.code & mask ) );
  1247.   return ev.code != evMOUSE_UP;
  1248. }
  1249. #endif
  1250.  
  1251. /*
  1252.   Description:
  1253.     Get (wait for) a keyboard event.
  1254.   Exit:
  1255.     ev: event.
  1256. */
  1257. void Titem::get_key( Tevent &ev, uint mask )
  1258. {
  1259.   do
  1260.   {
  1261.     get_event( ev );
  1262.   }
  1263.   while( !isit_4u( ev ) || !( ev.code & mask ) );
  1264. }
  1265.  
  1266. /*
  1267.   Description:
  1268.     Call owner's or 'hardware' put_event.
  1269.   Entry:
  1270.     ev: event to put.
  1271. */
  1272. void Titem::put_event( Tevent &ev )
  1273. {
  1274.   if( owner != NULL )
  1275.     owner->put_event( ev );
  1276.   else
  1277.     ::put_event( ev );
  1278. }
  1279.  
  1280. /*
  1281.   Description:
  1282.     Construct a command message and call put_event.
  1283.   Entry:
  1284.     receiver: pointer to the receiver, or NULL.
  1285.     cmd_code: command code.
  1286. */
  1287. void Titem::put_command( Titem *receiver, uint cmd_code )
  1288. {
  1289.   Tevent ev;
  1290.  
  1291.   ev.code = evCOMMAND;
  1292.   ev.priority = 0;
  1293.   ev.destination = receiver;
  1294.   ev.CMD_CODE = cmd_code;
  1295.   ev.CMD_INFO = command_information;
  1296.   ev.CMD_SIZE = command_size;
  1297.   put_event( ev );
  1298. }
  1299.  
  1300. /*
  1301.   Description:
  1302.     Called from an event_handler to indicate that event has been
  1303.     successfully handled.
  1304.   Entry:
  1305.     ev: handled event.
  1306. */
  1307. void Titem::handled( Tevent &ev )
  1308. {
  1309.   ev.code = evNOTHING;
  1310.   ev.destination = this;
  1311. }
  1312.  
  1313. /*
  1314.   Description:
  1315.     Terminate exec loop by stop_code.
  1316.   Entry:
  1317.     stop_code.
  1318. */
  1319. void Titem::stop( uint stop_code )
  1320. {
  1321.   if( state( isMODAL ) )
  1322.   {
  1323.     if( valid( stop_code ) ) stop_state = stop_code;
  1324.   }
  1325.   else
  1326.     owner->stop( stop_code );
  1327. }
  1328.  
  1329. /*
  1330.   Description:
  1331.     Called when user accept a dialog box, allowing item to update its
  1332.     information.
  1333. */
  1334. void Titem::ok_item( void )
  1335. {
  1336.   Titem *p;
  1337.  
  1338.   p = first();
  1339.   while( p != NULL )
  1340.   {
  1341.     p->ok_item();
  1342.     p = p->nextl();
  1343.   }
  1344. }
  1345.  
  1346. /*
  1347.   Description:
  1348.     Called when user cancel a dialog box, allowing item to undo changes.
  1349. */
  1350. void Titem::cancel_item( void )
  1351. {
  1352.   Titem *p;
  1353.  
  1354.   p = first();
  1355.   while( p != NULL )
  1356.   {
  1357.     p->cancel_item();
  1358.     p = p->nextl();
  1359.   }
  1360. }
  1361.  
  1362. /*
  1363.   Description:
  1364.     Called whenever subitems list has been changed and shoud pop the
  1365.     'always on top' items to the top.
  1366. */
  1367. void Titem::pop_top_items( void )
  1368. {
  1369.   if( items_changed && ( last != NULL ) ) do_pop_top_items( last );
  1370. }
  1371.  
  1372. boolean Titem::cenabled( uint cmd )
  1373. {
  1374.   if( owner != NULL ) return owner->cenabled( cmd );
  1375.   return ::cenabled( cmd );
  1376. }
  1377.  
  1378. boolean Titem::cdisabled( uint cmd )
  1379. {
  1380.   if( owner != NULL ) return owner->cdisabled( cmd );
  1381.   return ::cdisabled( cmd );
  1382. }
  1383.  
  1384. void Titem::cenable( uint cmd )
  1385. {
  1386.   if( owner != NULL )
  1387.     owner->cenable( cmd );
  1388.   else
  1389.     ::cenable( cmd );
  1390. }
  1391.  
  1392. void Titem::cdisable( uint cmd )
  1393. {
  1394.   if( owner != NULL )
  1395.     owner->cdisable( cmd );
  1396.   else
  1397.     ::cdisable( cmd );
  1398. }
  1399.  
  1400. void Titem::cstate( uint cmd, boolean enable )
  1401. {
  1402.   if( owner != NULL )
  1403.     owner->cstate( cmd, enable );
  1404.   else
  1405.     ::cstate( cmd, enable );
  1406. }
  1407.  
  1408. /*
  1409.   Description:
  1410.     Called when user drop an object over the item. Used for drag&drop.
  1411.   Entry:
  1412.     data: pointer dropped data.
  1413. */
  1414. void Titem::drop( void *data )
  1415. {
  1416.   Titem *p;
  1417.  
  1418.   p = first();
  1419.   while( p != NULL )
  1420.   {
  1421.     if( p->drop_id == drop_id ) p->drop( data );
  1422.     p = p->nextl();
  1423.   }
  1424. }
  1425.  
  1426.  
  1427. //Titem private:
  1428.  
  1429. /*
  1430.   Description:
  1431.     Return the help context of the item. If item has no help context
  1432.     return the owner's help context, and so on.
  1433. */
  1434. #ifndef NOHELP
  1435. uint Titem::get_help_ctx( void )
  1436. {
  1437.   Titem *p;
  1438.   uint ht;
  1439.  
  1440.   ht = help_ctx;
  1441.   p = owner;
  1442.   while( !ht && ( p != NULL ) )
  1443.   {
  1444.     ht = p->help_ctx;
  1445.     p = p->owner;
  1446.   }
  1447.   help_ctx = ht;
  1448.   p = first();
  1449.   while( p != NULL )
  1450.   {
  1451.     p->get_help_ctx();
  1452.     p = p->nextl();
  1453.   }
  1454.   return ht;
  1455. }
  1456. #endif
  1457.  
  1458.  
  1459. void Titem::do_pop_top_items( Titem *p )
  1460. {
  1461.   static Titem *l, *i;
  1462.  
  1463.   p = p->next;
  1464.   if( p != last ) do_pop_top_items( p );
  1465.   if( p->state( isON_TOP ) )
  1466.   {
  1467.     i = last;
  1468.     do
  1469.     {
  1470.       l = i;
  1471.       i = i->next;
  1472.     }
  1473.     while( i != p );
  1474.     if( p == last )
  1475.       last = l;
  1476.     else
  1477.     {
  1478.       l->next = p->next;
  1479.       p->next = last->next;
  1480.       last->next = p;
  1481.     }
  1482.   }
  1483. }
  1484.  
  1485.  
  1486. #ifndef NOMOUSE
  1487.  
  1488. //Tdrag_drop
  1489.  
  1490. class Tdrag_drop: public Titem
  1491. {
  1492.   public:
  1493.     long id;
  1494.     void *data;
  1495.     Tdraw_proc draw_proc;
  1496.     boolean can_drop;
  1497.     Tdrag_drop( int _xl, int _yl, long _id, void *_data, Tdraw_proc _draw_proc );
  1498.  
  1499.   protected:
  1500.     virtual void set_palette( void );
  1501.     virtual void draw( void );
  1502.     virtual boolean isit_4u( Tevent &ev );
  1503.     virtual void event_handler( Tevent &ev );
  1504.     Titem *get_drop_item( Titem *p, int _x, int _y );
  1505. };
  1506.  
  1507. static int current_xl = 0;
  1508. static int current_yl = 0;
  1509. static Tdraw_proc current_draw_proc = NULL;
  1510.  
  1511. void _drag_draw( int xl, int yl, Tdraw_proc draw_proc )
  1512. {
  1513.   current_xl = xl;
  1514.   current_yl = yl;
  1515.   current_draw_proc = draw_proc;
  1516. }
  1517.  
  1518. void pick_up( int x, int y, long id, void *data )
  1519. {
  1520.   int xl, yl;
  1521.   Tdrag_drop *drag_drop;
  1522.  
  1523.   xl = 2; yl = 1;
  1524.   if( current_xl )
  1525.   {
  1526.     xl = current_xl;
  1527.     yl = current_yl;
  1528.   }
  1529.   drag_drop = NEW( Tdrag_drop( xl, yl, id, data, current_draw_proc ) );
  1530.   current_xl = 0; current_draw_proc = NULL;
  1531.   application->make_local( x, y, x, y );
  1532.   application->put_in( drag_drop, x, y );
  1533. }
  1534.  
  1535. //Tdrag_drop publics:
  1536.  
  1537. Tdrag_drop::Tdrag_drop( int _xl, int _yl, long _id, void *_data, Tdraw_proc _draw_proc ):
  1538.   Titem( _xl, _yl )
  1539. {
  1540.   set_flags( ifRESIZEABLE+ifSELECTABLE, 0 );
  1541.   set_state( isON_TOP+isHIDDEN, 1 );
  1542.   id = _id;
  1543.   data = _data;
  1544.   draw_proc = _draw_proc;
  1545.   can_drop = 0;
  1546. }
  1547.  
  1548. //Tdrag_drop protected:
  1549.  
  1550. void Tdrag_drop::set_palette( void )
  1551. {
  1552.   if( can_drop )
  1553.     text_attr = pal_drag_drop.normal;
  1554.   else
  1555.     text_attr = pal_drag_drop.disabled;
  1556. }
  1557.  
  1558. void Tdrag_drop::draw( void )
  1559. {
  1560.   if( draw_proc != NULL )
  1561.     draw_proc();
  1562.   else
  1563.     direct_txt( "  " );
  1564. }
  1565.  
  1566. boolean Tdrag_drop::isit_4u( Tevent &ev )
  1567. {
  1568.   if( ev.code & evMOUSE )
  1569.   {
  1570.     make_local( ev.GLOBAL_X, ev.GLOBAL_Y, ev.LOCAL_X, ev.LOCAL_Y );
  1571.     ev.INSIDE = check_inside( ev.GLOBAL_X, ev.GLOBAL_Y );
  1572.     return 1;
  1573.   }
  1574.   return Titem::isit_4u( ev );
  1575. }
  1576.  
  1577. void Tdrag_drop::event_handler( Tevent &ev )
  1578. {
  1579.   int xx, yy;
  1580.   Titem *p;
  1581.  
  1582.   Titem::event_handler( ev );
  1583.   switch( ev.code )
  1584.   {
  1585.     case evMOUSE_DRAG:
  1586.       set_state( isHIDDEN, 0 );
  1587.       owner->make_local( ev.GLOBAL_X, ev.GLOBAL_Y, xx, yy );
  1588.       drag( xx, yy );
  1589.       p = get_drop_item( application, ev.GLOBAL_X, ev.GLOBAL_Y );
  1590.       can_drop = p->drop_id == id;
  1591.       handled( ev );
  1592.       break;
  1593.     case evMOUSE_UP:
  1594.       if( can_drop && !state( isHIDDEN ) )
  1595.         get_drop_item( application, ev.GLOBAL_X, ev.GLOBAL_Y )->drop( data );
  1596.       put_command( this, cmDONE );
  1597.       handled( ev );
  1598.   }
  1599. }
  1600.  
  1601. Titem *Tdrag_drop::get_drop_item( Titem *p, int _x, int _y )
  1602. {
  1603.   Titem *i;
  1604.  
  1605.   i = p->first();
  1606.   while( i != NULL )
  1607.   {
  1608.     if( i->state( isALIVE ) &&
  1609.         i->check_inside( _x, _y ) &&
  1610.         ( i != this ) )
  1611.       return get_drop_item( i, _x, _y );
  1612.     i = i->nextl();
  1613.   }
  1614.   return p;
  1615. }
  1616.  
  1617. #endif
  1618.